<?php

class LocalDirectory implements PhotoSource_I {

    public $site;
    private $dir;

    public function __construct(Site $site, $directory)
    {
        $this->site = $site;
        $this->dir = $directory;
    }

    public function getAlbum($id)
    {
        $id = self::cleanPath($id);
        return new LocalAlbum($this, $id);
    }

    public function getPhoto($id)
    {
        $id = self::cleanPath($id);
        $path_parts = pathinfo($this->getBaseDir() . $id);
        if (strtolower($path_parts['extension']) == 'mov') {
            return new LocalMovie($this, $id);    
        } else {
            return new LocalPhoto($this, $id);
        }
    }

    public function getDefaultAlbum()
    {
        return new LocalAlbum($this, "/");
    }

    public function getBaseDir()
    {
        return $this->dir;
    }

    public static function cleanPath($path)
    {
        if ($path[0] == '/') $abs = true; else $abs = false;
        // resolve path parts (single dot, double dot and double delimiters)
        $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
        $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
        $absolutes = array();
        foreach ($parts as $part) {
            if ('.'  == $part) continue;
            if ('..' == $part) {
                array_pop($absolutes);
            } else {
                $absolutes[] = $part;
            }
        }
        $path=implode(DIRECTORY_SEPARATOR, $absolutes);
        if ($abs) $path = '/' . $path;
        return $path;
    }
}

class LocalAlbum implements Album_I {

    private $source;
    private $id;
    private $contents;
    private $contents_dir_index;
    private $contents_file_index;
    private $full_path;

    public function __construct(LocalDirectory &$source, $id)
    {
        $this->source = $source;
        $this->id = $id;
        $this->full_path = LocalDirectory::cleanPath($this->source->getBaseDir() . '/' . $this->id);
    }

    public function getTitle()
    {
        if ($this->source->site->database->works()) {
            if ($title = $this->source->site->database->getValue($this->id, 'title')) {
                return $title;
            }
        }
        return basename($this->id);
    }

    public function getId()
    {
        return $this->id;
    }

    public function getNextSubAlbum()
    {
        $contents = $this->getContents();
        $num_entries = count($contents);
        error_log("this folder has $num_entries number of entries");
        while ($this->contents_dir_index < $num_entries) {
            error_log("checking entry number {$this->contents_dir_index}");
            if ($contents[$this->contents_dir_index][0] == '.') {
                $this->contents_dir_index++;
                continue;
            }
            $new_id = LocalDirectory::cleanPath($this->id . '/' . $contents[$this->contents_dir_index]);
            if (!is_dir($this->source->getBaseDir() . $new_id)) {
                $this->contents_dir_index++;
                continue;
            }
            $this->contents_dir_index++;
            return new LocalAlbum($this->source, $new_id);
        }
        return false;
    }

    public function getNextPhoto()
    {
        $contents = $this->getContents();
        $num_entries = count($contents);
        while ($this->contents_file_index < $num_entries) {
            if ($contents[$this->contents_file_index][0] == '.') {
                $this->contents_file_index++;
                continue;
            }
            $new_id = LocalDirectory::cleanPath($this->id . '/' . $contents[$this->contents_file_index]);
            $new_full_path = $this->source->getBaseDir() . $new_id;
            $path_parts = pathinfo($new_full_path);
            $is_movie = (strtolower($path_parts['extension']) == 'mov');
            if (!$is_movie && @exif_imagetype($new_full_path) != true) {
                $this->contents_file_index++;
                continue;
            }
            $this->contents_file_index++;
            if ($is_movie) {
                return new LocalMovie($this->source, $new_id);    
            } else {
                return new LocalPhoto($this->source, $new_id);
            }
        }
        return false;
    }

    private function getContents()
    {
        if (isset($this->contents)) return $this->contents;
        error_log("Getting contents of {$this->full_path}");
        $this->contents = scandir($this->full_path);
        $this->contents_dir_index = 0;
        $this->contents_file_index = 0;
        return $this->contents;
    }
}

class LocalPhoto implements UriPhoto_I {

    private $source;
    private $id;
    private $exif;
    protected $full_path;
    private $exif_thumbnail_dims = NULL;

    public function __construct(LocalDirectory $source, $id)
    {
        $this->source = $source;
        $this->id = $id;
        $this->full_path = $this->source->getBaseDir() . $this->id;
        error_log("Full path = {$this->full_path}");
    }

    public function getTitle()
    {
        if ($this->source->site->database->works()) {
            if ($title = $this->source->site->database->getValue($this->id, 'title')) {
                return $title;
            }
        }
        return basename($this->id);
    }

    public function getId()
    {
        return $this->id;
    }
    
    public function getPath()
    {
        return $this->full_path;    
    }
    
    public function getExifThumbnail()
    {
        exif_thumbnail($this->full_path, $exif_width, $exif_height);
        $this->exif_thumbnail_dims = new Dims($exif_width, $exif_height);
    }
    
    public function getExifThumbnailDims()
    {
        if ($this->exif_thumbnail_dims == NULL) {
            $this->getExifThumbnail();    
        }
        return $this->exif_thumbnail_dims;
    }

    private function getExif()
    {
        if (!isset($this->exif)) {
            $this->exif = exif_read_data($this->full_path);
        }
        return $this->exif;
    }

    public function getMetadata($name, $calculated=false)
    {
        $exif = $this->getExif();
        if ($calculated) {
            return $exif['CALCULATED'][$name];
        }
        return $exif[$name];
    }
}

class LocalMovie extends LocalPhoto implements UriMovie_I
{
    public function getPath()
    {
        return $this->full_path;    
    }
}